package tjs.study.mini.spingmvcmini.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.AbstractRefreshableConfigApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @author nicky
 * @date 2021/9/7 下午2:17
 */
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableConfigApplicationContext implements AnnotationConfigRegistry {

    private final Set<Class<?>> componentClasses = new LinkedHashSet<>();
    private final Set<String> basePackages = new LinkedHashSet<>();

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        if (!componentClasses.isEmpty()) {
            AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory, getEnvironment());
            reader.register(ClassUtils.toClassArray(this.componentClasses));
        }

        if (!this.basePackages.isEmpty()) {
            ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
            scanner.scan(StringUtils.toStringArray(this.basePackages));
        }
    }

    @Override
    public void register(Class<?>... componentClasses) {
        Assert.notEmpty(componentClasses, "At least one component class must be specified");
        Collections.addAll(this.componentClasses, componentClasses);
    }

    @Override
    public void scan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Collections.addAll(this.basePackages, basePackages);
    }
}
